package services

import (
	"fmt"
	"log"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/domains"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/projects"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/roles"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/users"
)

type KeystoneService struct {
	client   *gophercloud.ServiceClient
	provider *gophercloud.ProviderClient
}

type ConfigValidationError struct {
	Type    string `json:"type"`
	Message string `json:"message"`
	Fix     string `json:"fix"`
}

type ValidationResult struct {
	Valid  bool                    `json:"valid"`
	Errors []ConfigValidationError `json:"errors"`
}

func NewKeystoneService(authURL, username, password, projectName, domainName string) (*KeystoneService, error) {
	authOptions := gophercloud.AuthOptions{
		IdentityEndpoint: authURL,
		Username:         username,
		Password:         password,
		TenantName:       projectName,
		DomainName:       domainName,
	}

	provider, err := openstack.AuthenticatedClient(authOptions)
	if err != nil {
		return nil, fmt.Errorf("认证失败: %v", err)
	}

	client, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{
		Region: "RegionOne",
	})
	if err != nil {
		return nil, fmt.Errorf("创建Keystone客户端失败: %v", err)
	}

	return &KeystoneService{
		client:   client,
		provider: provider,
	}, nil
}

func (ks *KeystoneService) ValidateConfiguration(config map[string]interface{}) ValidationResult {
	var errors []ConfigValidationError

	// 验证企业域
	if err := ks.validateDomain(config); err != nil {
		errors = append(errors, *err)
	}

	// 验证必需角色
	if errs := ks.validateRoles(config); len(errs) > 0 {
		errors = append(errors, errs...)
	}

	// 验证项目和配额
	if errs := ks.validateProjects(config); len(errs) > 0 {
		errors = append(errors, errs...)
	}

	// 验证用户和权限
	if errs := ks.validateUsers(config); len(errs) > 0 {
		errors = append(errors, errs...)
	}

	return ValidationResult{
		Valid:  len(errors) == 0,
		Errors: errors,
	}
}

func (ks *KeystoneService) validateDomain(config map[string]interface{}) *ConfigValidationError {
	enterpriseConfig := config["enterprise"].(map[string]interface{})
	domainName := enterpriseConfig["domain_name"].(string)

	allPages, err := domains.List(ks.client, domains.ListOpts{Name: domainName}).AllPages()
	if err != nil {
		return &ConfigValidationError{
			Type:    "domain_error",
			Message: fmt.Sprintf("无法查询域 '%s': %v", domainName, err),
			Fix:     fmt.Sprintf("请检查Keystone连接配置"),
		}
	}

	domainList, err := domains.ExtractDomains(allPages)
	if err != nil || len(domainList) == 0 {
		return &ConfigValidationError{
			Type:    "domain_missing",
			Message: fmt.Sprintf("域 '%s' 不存在", domainName),
			Fix:     fmt.Sprintf("openstack domain create %s", domainName),
		}
	}

	log.Printf("✓ 检查域 '%s' ... 存在", domainName)
	return nil
}

func (ks *KeystoneService) validateRoles(config map[string]interface{}) []ConfigValidationError {
	var errors []ConfigValidationError
	requiredRoles := config["required_roles"].([]interface{})

	for _, roleConfig := range requiredRoles {
		roleName := roleConfig.(map[string]interface{})["name"].(string)

		allPages, err := roles.List(ks.client, roles.ListOpts{Name: roleName}).AllPages()
		if err != nil {
			errors = append(errors, ConfigValidationError{
				Type:    "role_query_error",
				Message: fmt.Sprintf("无法查询角色 '%s': %v", roleName, err),
				Fix:     "请检查Keystone连接配置",
			})
			continue
		}

		roleList, err := roles.ExtractRoles(allPages)
		if err != nil || len(roleList) == 0 {
			errors = append(errors, ConfigValidationError{
				Type:    "role_missing",
				Message: fmt.Sprintf("角色 '%s' 不存在", roleName),
				Fix:     fmt.Sprintf("openstack role create %s", roleName),
			})
		} else {
			log.Printf("✓ 检查角色 '%s' ... 存在", roleName)
		}
	}

	return errors
}

func (ks *KeystoneService) validateProjects(config map[string]interface{}) []ConfigValidationError {
	var errors []ConfigValidationError

	enterpriseConfig := config["enterprise"].(map[string]interface{})
	domainName := enterpriseConfig["domain_name"].(string)

	// 获取域ID
	domainID, err := ks.getDomainID(domainName)
	if err != nil {
		errors = append(errors, ConfigValidationError{
			Type:    "domain_id_error",
			Message: fmt.Sprintf("无法获取域ID: %v", err),
			Fix:     "请检查域名配置",
		})
		return errors
	}

	requiredProjects := config["required_projects"].([]interface{})
	for _, projConfig := range requiredProjects {
		projectData := projConfig.(map[string]interface{})
		projectName := projectData["name"].(string)

		allPages, err := projects.List(ks.client, projects.ListOpts{
			DomainID: domainID,
			Name:     projectName,
		}).AllPages()

		if err != nil {
			errors = append(errors, ConfigValidationError{
				Type:    "project_query_error",
				Message: fmt.Sprintf("无法查询项目 '%s': %v", projectName, err),
				Fix:     "请检查Keystone连接配置",
			})
			continue
		}

		projectList, err := projects.ExtractProjects(allPages)
		if err != nil || len(projectList) == 0 {
			errors = append(errors, ConfigValidationError{
				Type:    "project_missing",
				Message: fmt.Sprintf("项目 '%s' 不存在", projectName),
				Fix:     fmt.Sprintf("openstack project create --domain %s %s", domainName, projectName),
			})
		} else {
			log.Printf("✓ 检查项目 '%s' ... 存在", projectName)
		}
	}

	return errors
}

func (ks *KeystoneService) validateUsers(config map[string]interface{}) []ConfigValidationError {
	var errors []ConfigValidationError

	enterpriseConfig := config["enterprise"].(map[string]interface{})
	domainName := enterpriseConfig["domain_name"].(string)

	domainID, err := ks.getDomainID(domainName)
	if err != nil {
		return []ConfigValidationError{{
			Type:    "domain_validation_error",
			Message: fmt.Sprintf("域验证失败: %v", err),
			Fix:     "请先完成域的创建和配置",
		}}
	}

	testAccounts := config["test_accounts"].(map[string]interface{})

	for accountType, accountConfig := range testAccounts {
		accountData := accountConfig.(map[string]interface{})
		username := accountData["username"].(string)
		password := accountData["password"].(string)

		// 验证用户存在
		userID, err := ks.getUserID(username, domainID)
		if err != nil {
			errors = append(errors, ConfigValidationError{
				Type:    "user_missing",
				Message: fmt.Sprintf("用户 '%s' 不存在", username),
				Fix:     fmt.Sprintf("openstack user create --domain %s --password %s %s", domainName, password, username),
			})
			continue
		}

		// 验证用户认证
		if err := ks.validateUserAuth(username, password, domainName); err != nil {
			errors = append(errors, ConfigValidationError{
				Type:    "auth_failed",
				Message: fmt.Sprintf("用户 '%s' 认证失败", username),
				Fix:     "检查config.yaml中的密码是否与实际创建时一致",
			})
		}

		// 验证项目权限
		if expectedProjects, exists := accountData["expected_projects"]; exists {
			projectList := expectedProjects.([]interface{})
			expectedRoles := accountData["expected_roles"].([]interface{})

			for _, proj := range projectList {
				projectName := proj.(string)
				projectID, err := ks.getProjectID(projectName, domainID)
				if err != nil {
					continue // 项目不存在的错误已在validateProjects中处理
				}

				for _, role := range expectedRoles {
					roleName := role.(string)
					if !ks.userHasProjectRole(userID, projectID, roleName) {
						errors = append(errors, ConfigValidationError{
							Type:    "permission_missing",
							Message: fmt.Sprintf("用户 '%s' 缺少项目 '%s' 的 '%s' 权限", username, projectName, roleName),
							Fix:     fmt.Sprintf("openstack role add --project %s --user %s %s", projectName, username, roleName),
						})
					}
				}
			}
		}

		// 验证域权限
		if domainRoles, exists := accountData["domain_roles"]; exists {
			roleList := domainRoles.([]interface{})
			for _, role := range roleList {
				roleName := role.(string)
				if !ks.userHasDomainRole(userID, domainID, roleName) {
					errors = append(errors, ConfigValidationError{
						Type:    "domain_permission_missing",
						Message: fmt.Sprintf("用户 '%s' 缺少域 '%s' 的 '%s' 权限", username, domainName, roleName),
						Fix:     fmt.Sprintf("openstack role add --domain %s --user %s %s", domainName, username, roleName),
					})
				}
			}
		}

		if len(errors) == 0 {
			log.Printf("✓ 检查用户 '%s' (%s) ... 权限正确", username, accountType)
		}
	}

	return errors
}

func (ks *KeystoneService) getDomainID(domainName string) (string, error) {
	allPages, err := domains.List(ks.client, domains.ListOpts{Name: domainName}).AllPages()
	if err != nil {
		return "", err
	}

	domainList, err := domains.ExtractDomains(allPages)
	if err != nil || len(domainList) == 0 {
		return "", fmt.Errorf("域 '%s' 不存在", domainName)
	}

	return domainList[0].ID, nil
}

func (ks *KeystoneService) getUserID(username, domainID string) (string, error) {
	allPages, err := users.List(ks.client, users.ListOpts{
		DomainID: domainID,
		Name:     username,
	}).AllPages()
	if err != nil {
		return "", err
	}

	userList, err := users.ExtractUsers(allPages)
	if err != nil || len(userList) == 0 {
		return "", fmt.Errorf("用户 '%s' 不存在", username)
	}

	return userList[0].ID, nil
}

func (ks *KeystoneService) getProjectID(projectName, domainID string) (string, error) {
	allPages, err := projects.List(ks.client, projects.ListOpts{
		DomainID: domainID,
		Name:     projectName,
	}).AllPages()
	if err != nil {
		return "", err
	}

	projectList, err := projects.ExtractProjects(allPages)
	if err != nil || len(projectList) == 0 {
		return "", fmt.Errorf("项目 '%s' 不存在", projectName)
	}

	return projectList[0].ID, nil
}

func (ks *KeystoneService) validateUserAuth(username, password, domainName string) error {
	// 尝试使用项目scope认证，而不是域scope
	domainID, err := ks.getDomainID(domainName)
	if err != nil {
		return err
	}

	// 获取用户所属的项目列表进行认证测试
	userID, err := ks.getUserID(username, domainID)
	if err != nil {
		return err
	}

	userProjects, err := ks.getUserProjectsForAuth(userID, domainID)
	if err != nil || len(userProjects) == 0 {
		// 如果没有项目权限，尝试域级认证
		authOptions := gophercloud.AuthOptions{
			IdentityEndpoint: ks.provider.IdentityEndpoint,
			Username:         username,
			Password:         password,
			DomainName:       domainName,
			Scope: &gophercloud.AuthScope{
				DomainName: domainName,
			},
		}

		_, err = openstack.AuthenticatedClient(authOptions)
		return err
	}

	// 使用第一个项目进行认证测试
	authOptions := gophercloud.AuthOptions{
		IdentityEndpoint: ks.provider.IdentityEndpoint,
		Username:         username,
		Password:         password,
		TenantName:       userProjects[0].Name,
		DomainName:       domainName,
	}

	_, err = openstack.AuthenticatedClient(authOptions)
	return err
}

func (ks *KeystoneService) getUserProjectsForAuth(userID, domainID string) ([]projects.Project, error) {
	// 获取用户有权限的所有项目
	allPages, err := roles.ListAssignments(ks.client, roles.ListAssignmentsOpts{
		UserID: userID,
	}).AllPages()
	if err != nil {
		return nil, err
	}

	assignments, err := roles.ExtractRoleAssignments(allPages)
	if err != nil {
		return nil, err
	}

	var userProjects []projects.Project
	projectIDs := make(map[string]bool)

	// 提取项目级别的权限分配
	for _, assignment := range assignments {
		if assignment.Scope.Project.ID != "" {
			projectIDs[assignment.Scope.Project.ID] = true
		}
	}

	// 获取项目详情
	for projectID := range projectIDs {
		project, err := projects.Get(ks.client, projectID).Extract()
		if err == nil && project.DomainID == domainID {
			userProjects = append(userProjects, *project)
		}
	}

	return userProjects, nil
}

func (ks *KeystoneService) userHasProjectRole(userID, projectID, roleName string) bool {
	roleID, err := ks.getRoleID(roleName)
	if err != nil {
		return false
	}

	// 使用List方式检查用户角色分配
	allPages, err := roles.ListAssignments(ks.client, roles.ListAssignmentsOpts{
		UserID:         userID,
		ScopeProjectID: projectID,
		RoleID:         roleID,
	}).AllPages()
	if err != nil {
		return false
	}

	assignments, err := roles.ExtractRoleAssignments(allPages)
	return err == nil && len(assignments) > 0
}

func (ks *KeystoneService) userHasDomainRole(userID, domainID, roleName string) bool {
	roleID, err := ks.getRoleID(roleName)
	if err != nil {
		return false
	}

	// 使用List方式检查用户域角色分配
	allPages, err := roles.ListAssignments(ks.client, roles.ListAssignmentsOpts{
		UserID:        userID,
		ScopeDomainID: domainID,
		RoleID:        roleID,
	}).AllPages()
	if err != nil {
		return false
	}

	assignments, err := roles.ExtractRoleAssignments(allPages)
	return err == nil && len(assignments) > 0
}

func (ks *KeystoneService) getRoleID(roleName string) (string, error) {
	allPages, err := roles.List(ks.client, roles.ListOpts{Name: roleName}).AllPages()
	if err != nil {
		return "", err
	}

	roleList, err := roles.ExtractRoles(allPages)
	if err != nil || len(roleList) == 0 {
		return "", fmt.Errorf("角色 '%s' 不存在", roleName)
	}

	return roleList[0].ID, nil
}

func (ks *KeystoneService) AuthenticateUser(username, password, domainName, projectName string) (*UserContext, error) {
	// 获取域ID
	domainID, err := ks.getDomainID(domainName)
	if err != nil {
		return nil, fmt.Errorf("域查询失败: %v", err)
	}

	// 获取用户ID
	userID, err := ks.getUserID(username, domainID)
	if err != nil {
		return nil, fmt.Errorf("用户不存在: %v", err)
	}

	// 获取用户项目列表用于认证
	userProjects, err := ks.getUserProjectsForAuth(userID, domainID)
	if err != nil {
		return nil, fmt.Errorf("获取用户项目失败: %v", err)
	}

	// 如果指定了项目名，使用指定项目；否则使用第一个可用项目
	var authProject string
	if projectName != "" {
		authProject = projectName
	} else if len(userProjects) > 0 {
		authProject = userProjects[0].Name
	} else {
		return nil, fmt.Errorf("用户没有任何项目权限")
	}

	// 进行实际认证
	authOptions := gophercloud.AuthOptions{
		IdentityEndpoint: ks.provider.IdentityEndpoint,
		Username:         username,
		Password:         password,
		TenantName:       authProject,
		DomainName:       domainName,
	}

	provider, err := openstack.AuthenticatedClient(authOptions)
	if err != nil {
		return nil, fmt.Errorf("用户认证失败: %v", err)
	}

	// 获取用户角色
	userRoles, err := ks.getUserRoles(userID, domainID)
	if err != nil {
		return nil, fmt.Errorf("获取用户角色失败: %v", err)
	}

	// 创建用户上下文
	userContext := &UserContext{
		Username:    username,
		ProjectName: authProject,
		DomainName:  domainName,
		Token:       provider.Token(),
		Roles:       userRoles,
	}

	return userContext, nil
}

type UserContext struct {
	Username    string   `json:"username"`
	ProjectName string   `json:"project_name"`
	DomainName  string   `json:"domain_name"`
	Token       string   `json:"token"`
	Roles       []string `json:"roles"`
}

func (ks *KeystoneService) GetUserProjects(userID, domainID string) ([]projects.Project, error) {
	allPages, err := projects.List(ks.client, projects.ListOpts{
		DomainID: domainID,
	}).AllPages()
	if err != nil {
		return nil, err
	}

	return projects.ExtractProjects(allPages)
}

func (ks *KeystoneService) getUserRoles(userID, domainID string) ([]string, error) {
	// 获取用户的所有角色分配
	allPages, err := roles.ListAssignments(ks.client, roles.ListAssignmentsOpts{
		UserID: userID,
	}).AllPages()
	if err != nil {
		return nil, err
	}

	assignments, err := roles.ExtractRoleAssignments(allPages)
	if err != nil {
		return nil, err
	}

	roleIDs := make(map[string]bool)
	for _, assignment := range assignments {
		// 收集项目级和域级的角色
		if assignment.Scope.Project.ID != "" || assignment.Scope.Domain.ID == domainID {
			roleIDs[assignment.Role.ID] = true
		}
	}

	// 获取角色名称
	var userRoles []string
	for roleID := range roleIDs {
		role, err := roles.Get(ks.client, roleID).Extract()
		if err == nil {
			userRoles = append(userRoles, role.Name)
		}
	}

	return userRoles, nil
}
